#include "set.h"
#include "shebei.h"
#include "ui_set.h"
#include "globalval.h"
#include "mqtthandler.h"

set::set(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::set)
{
    ui->setupUi(this);

    //初始化创建QUdpSocket对象套接字
    udpSocket = new QUdpSocket();

    // 创建tcp连接套接字
    tcp_beat_socket = new QTcpSocket(this);  // 心跳包套接字
    tcp_point_socket = new QTcpSocket(this);  // 下发点表套接字

    //mqtt相关,创建mqtt对象
    mqtt = new MqttHandler;
    GlobalVal::mqtt = mqtt;

//    mqtt->setHost(QHostAddress("192.168.59.128"));
//    mqtt->setPort(1883);
//    mqtt->connectToHost();

    // 刚开始连接与断开连接按钮不可选
    ui->pushButton_Connect->setEnabled(false);
    ui->pushButton_Discount->setEnabled(false);

    // 搜索按钮连接槽函数
    connect(ui->pushButton_Search,SIGNAL(clicked()),this,SLOT(pushButton_Search_Click()));
    // 断连按钮连接槽函数
    connect(ui->pushButton_Discount,SIGNAL(clicked()),this,SLOT(pushButton_Disconnect_Click()));

    // udp接收消息触发的槽函数
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(udp_recv_data()));

    // 心跳检测接收消息触发的槽函数
    connect(tcp_beat_socket,SIGNAL(readyRead()),this,SLOT(tcp_recv_data()));

    // 点击连接按钮心跳检测连接
    connect(ui->pushButton_Connect,SIGNAL(clicked()),this,SLOT(pushButton_Connect_Click()));
    // 连接成功状态槽函数
    connect(tcp_beat_socket,SIGNAL(connected()),this,SLOT(Connected_beat_Slot()));   // 心跳连接成功槽函数
    connect(tcp_point_socket,SIGNAL(connected()),this,SLOT(Connected_OK_Slot()));  // tcp点表发送连接成功槽函数
    // 断开连接状态槽函数
    connect(tcp_beat_socket,SIGNAL(disconnected()),this,SLOT(Beatdis_Connected_Slot()));  // 心跳连接断开槽函数
    connect(tcp_point_socket,SIGNAL(disconnected()),this,SLOT(Dis_Connected_Slot()));  // tcp连接断开槽函数

    timer = new QTimer(this); //创建定时器
    connect(timer, SIGNAL(timeout()), this,SLOT(tcp_Headbeat_Slot()));
    timer->setInterval(3000); // 设置定时器间隔为3000毫秒（3秒）

    // 上报模式切换连接槽函数
    connect(ui->comboBox_System,SIGNAL(currentTextChanged(QString)),this,SLOT(System_Change_Slot(QString)));

    //发射信号连接mqtt服务器
    connect(this,SIGNAL(mqtt_connect()),this,SLOT(mqtt_Connect()));

}

set::~set()
{
    delete ui;
}


// 上报模式切换 ，只有当模式改变时才进入到此槽函数
void set::System_Change_Slot(QString text)
{
    // 创建JSON对象
    QJsonObject SystemObject;
    QByteArray jsonString;
    SystemObject["version"] = "v1.0";

    // 创建JSON对象
    QJsonObject reportObject;

    if(text == QString("刷新上报"))  // 刷新上报
    {
        // 添加两个节点数据
        reportObject["type"] = 0;
        reportObject["period"] = 0;
        // 将 reportObject 添加到 systemObject 中
        SystemObject["report"] = reportObject;
        // 将JSON对象序列化为文档
        QJsonDocument jsonDoc(SystemObject);
        // 将文档转换为字符串（QByteArray）
        jsonString = jsonDoc.toJson(QJsonDocument::Compact);

        qDebug() << "修改为刷新上报" ;
    }

    if(text == QString("变化上报"))  // 变化上报
    {
        reportObject["type"] = 1;
        reportObject["period"] = 0;
        // 将 reportObject 添加到 systemObject 中
        SystemObject["report"] = reportObject;
        // 将JSON对象序列化为文档
        QJsonDocument jsonDoc(SystemObject);
        // 将文档转换为字符串（QByteArray）
        jsonString = jsonDoc.toJson(QJsonDocument::Compact);

        qDebug() << "修改为变化上报";

    }

    if(text == QString("周期上报"))  // 周期上报
    {
        if(ui->lineEdit_miao->text().isEmpty())
        {
            QMessageBox::warning(this,"提示","请输入上报周期");
        }

        reportObject["type"] = 2;
        reportObject["period"] = ui->lineEdit_miao->text().toInt();
        // 将 reportObject 添加到 systemObject 中
        SystemObject["report"] = reportObject;
        // 将JSON对象序列化为文档
        QJsonDocument jsonDoc(SystemObject);
        // 将文档转换为字符串（QByteArray）
        jsonString = jsonDoc.toJson(QJsonDocument::Compact);

        qDebug() << "修改为周期上报" ;
    }

    qDebug() << jsonString ;

    // 将json模式改变的数据通过mqtt发送到服务器
    QMQTT::Message message;
    message.setTopic(GlobalVal::topic);
    qDebug() << GlobalVal::topic;
    message.setPayload(jsonString);

    quint16 result = GlobalVal::mqtt->publish(message);
    if (result == 0)
    {
        qDebug() << "Message published successfully.";
    }
    else
    {
         qDebug() << "Failed to publish message. Error code:" << result;
    }


}

// 进行mqtt连接的槽函数
void set::mqtt_Connect()
{
    GlobalVal::mqtt->connectToHost();
    qDebug() << "进行mqtt连接";
}


// udp广播槽函数
void set::pushButton_Search_Click()
{
    // 判断是否输入了广播地址与端口
    if(ui->lineEdit_udpip->text().isEmpty() || ui->lineEdit_udppost->text().isEmpty())
    {
        QMessageBox::warning(this,"提示","请输入广播ip和端口号");
    }
    // 获取输入的IP地址与端口
    udp_search_addrees.setAddress( ui->lineEdit_udpip->text());
    udp_search_Port  = ui->lineEdit_udppost->text().toInt();

    qDebug() << "From IP:" << ui->lineEdit_udpip->text() << " Port:" << ui->lineEdit_udppost->text().toInt() ;

    // 自定义协议，writeDatagram发送数据需要转成 QByteArray类型
    QString data = "sizu";
    QByteArray senddata = data.toUtf8();

    // 广播发送数据
    udpSocket->writeDatagram(senddata,udp_search_addrees,udp_search_Port);
    qDebug() << "已经广播了数据：" << data ;

}


// udp接收槽函数
void set::udp_recv_data()
{
    QByteArray datagram;
    // 检查是否有待处理的数据报
    if (udpSocket->hasPendingDatagrams())
    {
        // 根据待处理数据报的大小调整datagram的大小
        datagram.resize(udpSocket->pendingDatagramSize());

        // 读取数据报
        qint64 bytesRead = udpSocket->readDatagram(datagram.data(), datagram.size(), &tcp_address, &tcp_Port);
        if (bytesRead > 0)
        {
            // 调整 QByteArray 的大小以匹配实际读取的数据量
            datagram.truncate(bytesRead);

            // 打印发送端的IP地址与端口号
            qDebug() << "Received data:" << datagram;
            qDebug() << "From IP:" << tcp_address.toString() << "Port:" << tcp_Port;
        } else
        {
            qDebug() << "读取数据失败，但存在待处理的数据报";
        }
    }
    else
    {
        qDebug() << "没有待处理的数据报";
    }

    // 将发送端的IP地址与端口号填入
    // 将IP地址与端口号转换成字符串
    QString ipString = tcp_address.toString();
    QString postString = QString::number(tcp_Port);

    ui->lineEdit_tcpip->setText(ipString);
    ui->lineEdit_tcppost->setText(postString);

    //解锁连接按钮，可以进行连接
    ui->pushButton_Connect->setEnabled(true);
    qDebug() << "可以进行连接";
}



// 心跳检测连接槽函数
void set::pushButton_Connect_Click()
{
    // 心跳检测连接到服务器
    tcp_beat_socket->connectToHost(tcp_address,tcp_Port);

}

// 心跳检测连接成功响应的槽函数
void set::Connected_beat_Slot()
{
    // 禁用搜索按钮，释放断连按钮
    ui->pushButton_Search->setEnabled(false);
    ui->pushButton_Discount->setEnabled(true);
    qDebug() << "心跳检测连接成功，可以进行点表询问";
    tcp_qoint_data();  // 连接成功之后进行点表状态询问
}

// 进行发送点表的端口连接
void set::point_connect()
{
    timer->stop(); // 定时器停止，直到文件发送完成
    tcp_point_socket->connectToHost(tcp_address,tcp_Port+1);
    if (!tcp_point_socket->waitForConnected())
    {
        qDebug() << "连接失败：" << tcp_point_socket->errorString();
        return;
    }
    qDebug() << "tcp_point连接";


}

// tcp下发文件连接成功响应的槽函数
void set::Connected_OK_Slot()
{
    qDebug() << "tcp_point连接成功，可以进行发送点表";

}

//点击断开连接按钮对应的槽函数
void set::pushButton_Disconnect_Click()
{
    // 断开连接
    tcp_beat_socket->disconnectFromHost();
    tcp_point_socket->disconnectFromHost();

}

// 断开连接之后响应的槽函数
void set::Beatdis_Connected_Slot()
{
    // 释放搜索按钮，禁用连接与断连按钮
    ui->pushButton_Search->setEnabled(true);
    ui->pushButton_Connect->setEnabled(false);
    ui->pushButton_Discount->setEnabled(false);
    qDebug() << "心跳连接已断开";
}

// 发送点表的连接断开之后响应的槽函数
void set::Dis_Connected_Slot()
{
    qDebug() << "发送数据的连接已断开";


}

// 点表询问函数
void set::tcp_qoint_data()
{
    // 创建JSON对象
    QJsonObject jsonObject;
    jsonObject["type"] = 1;

    // 将JSON对象序列化为文档
    QJsonDocument jsonDoc(jsonObject);

    // 将文档转换为字符串（QByteArray）
    QByteArray jsonString = jsonDoc.toJson(QJsonDocument::Compact);

    // 发送JSON字符串
    tcp_beat_socket->write(jsonString);
}


// 心跳接收槽函数
void set::tcp_recv_data()
{
    // 读取套接字中的数据
    qoint_data = tcp_beat_socket->readAll();

    // 判断点表是否发送完成
    bool isOk;
    if (QString::fromUtf8(qoint_data) == "start")  //检测到服务器发送了start，开始发送点表
    {
        // tcp发送端口连接到服务器
        point_connect();
        QThread::msleep(1000);
        qoint_send_data();  // 跳转到发送点表函数
    }
    if(QString::fromUtf8(qoint_data) == "stop")  // 发送完成
    {
        tcp_point_socket->disconnectFromHost();  // 断开发送点表的端口连接
        return;
    }

    // 解析JSON数据
    QJsonParseError jsonError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(qoint_data, &jsonError);

    // 确保是一个对象
    if (!jsonDoc.isObject())
    {
        qDebug() << "tcp：JSON不是一个对象";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    // 访问JSON对象中的值
    // 解析点表状态信息
    int type = jsonObj.value("type").toInt();
    int result = jsonObj.value("result").toInt();
    bool up_config = jsonObj.value("up_config").toBool();

    qDebug() << "type：" << type;
    qDebug() << "result：" << result;
    qDebug() << "up_config：" << up_config;


    // 读取嵌套的data对象
    QJsonObject dataObject = jsonObj.value("data").toObject();
    // 解析mqtt服务器配置信息，读取mqtt_config
    QJsonObject mqttConfig = dataObject.value("mqtt_config").toObject();
    GlobalVal::mqttAddr = mqttConfig.value("mqtt_addr").toString();
    GlobalVal::mqttPort = mqttConfig.value("mqtt_port").toInt();

    qDebug() << "MQTT Address:" << GlobalVal::mqttAddr;
    qDebug() << "MQTT Port:" << GlobalVal::mqttPort;


    mqtt->setHost(QHostAddress(GlobalVal::mqttAddr));
    mqtt->setPort(GlobalVal::mqttPort);
    emit mqtt_connect();


    // 解析监控服务器配置信息，读取video_config
    QJsonObject videoConfig = dataObject.value("video_config").toObject();
    GlobalVal::videoAddr = videoConfig.value("video_addr").toString();
    GlobalVal::videoPort = videoConfig.value("video_port").toInt();

    qDebug() << "Video Address:" << GlobalVal::videoAddr;
    qDebug() << "Video Port:" << GlobalVal::videoPort;

    // 解析上报模式配置信息，读取update_config
    QJsonObject updateConfig = dataObject.value("update_config").toObject();
    int updateType = updateConfig.value("type").toInt();
    int updatePeriod = updateConfig.value("period").toInt();

    qDebug() << "Update Type:" << updateType;
    qDebug() << "Update Period:" << updatePeriod;

    // 判断是否需要下发点表
    if(type == 1)
    {
        if(up_config == true)
        {
            qDebug() << "需要下发点表" ;

            qoint_type_data();  // 发送点表文件信息
        }
        else
        {
            qDebug() << "不需要下发点表" ;
            // 开启心跳检测
            timer->start();

            // 检测定时器状态
            if (timer->isActive())
            {
                qDebug() << "定时器正在运行";
            }
            else
            {
                qDebug() << "定时器已停止";
            }
        }
    }

    // 判断心跳检测的回复
    if(type == 3)
    {
        if(result != 0)
        {
            qDebug() << "连接正常" ;
        }
        else
        {
            qDebug() << "连接异常" ;
        }
    }


}


// 点表状态通知
void set::qoint_type_data()
{
    // 创建JSON对象
    QJsonObject jsonObject;
    jsonObject["type"] = 2;

    // 将JSON对象序列化为文档
    QJsonDocument jsonDoc(jsonObject);

    // 将文档转换为字符串（QByteArray）
    QByteArray jsonString = jsonDoc.toJson(QJsonDocument::Compact);

    // 发送JSON字符串
    tcp_beat_socket->write(jsonString);
}

// 心跳检测发送槽函数
void set::tcp_Headbeat_Slot()
{
    // 创建JSON对象
    QJsonObject jsonObject;
    jsonObject["type"] = 3;

    // 将JSON对象序列化为文档
    QJsonDocument jsonDoc(jsonObject);

    // 将文档转换为字符串（QByteArray）
    QByteArray jsonString = jsonDoc.toJson(QJsonDocument::Compact);

    // 发送JSON字符串
    tcp_beat_socket->write(jsonString);
}


//点表发送函数
void set::qoint_send_data()
{
    // 创建文件对象
    QFileInfo fileInfo(readPath);
    if(!fileInfo.exists())
    {
        return;
    }

    // 获取文件大小
    qint64 fileSize = fileInfo.size();
    qDebug() << "文件大小：" << fileSize << "字节";


    // 获取文件名称
    QString text = fileInfo.baseName();
    qDebug() << "文件名称：" << text;


    // 获取文件可读性
    bool result = fileInfo.isReadable();
    if(result)
    {
        qDebug() << "文件可读";
    }
    else
    {
        qDebug() << "文件不可读";
    }

    QFile qoint_file(readPath);
    if (!qoint_file.open(QIODevice::ReadOnly))
    {
        // 处理打开文件失败的情况
        qDebug() << "文件打开失败";
        return;
    }

    // 循环读取文件内容并发送
    qint64 sentSize = 0;
    while (sentSize < fileSize)
    {
        QByteArray data = qoint_file.read(1023); // 读取一块数据
        qDebug() << data;

        if (tcp_point_socket->state() == QAbstractSocket::ConnectedState) {
            qint64 bytesWritten = tcp_point_socket->write(data);
            if (bytesWritten == -1) {
                qDebug() << "Failed to write data to socket.";
            } else {
                qDebug() << "Successfully wrote" << bytesWritten << "bytes to socket.";
            }
        } else {
            qDebug() << "Socket is not connected.";
        }
        sentSize += data.size();
        qDebug() << sentSize;
        tcp_point_socket->flush(); // 确保数据被发送

    }

    // 文件发送完成，开启定时器进行心跳检测
    timer->start();

    // 检测定时器状态
    if (timer->isActive())
    {
        qDebug() << "定时器正在运行";
    }
    else
    {
        qDebug() << "定时器已停止";
    }
}
